"""
Email Service Main Application
Handles all email-related functionality including notifications, digests, and alerts
"""

import asyncio
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
import json

from fastapi import FastAPI, BackgroundTasks, HTTPException
from pydantic import BaseModel, EmailStr
import uvicorn

from config import get_config
from email_service.email_manager import EmailManager
from email_service.notification_processor import NotificationProcessor
from email_service.template_manager import TemplateManager
from services.database_manager import DatabaseManager

logger = logging.getLogger(__name__)

# Configuration
config = get_config()

# Email service application
email_app = FastAPI(
    title="ArXiv Email Service",
    description="Email notifications and digest service for ArXiv subscription platform",
    version="1.0.0"
)

# Service instances
email_manager = EmailManager()
notification_processor = NotificationProcessor()
template_manager = TemplateManager()
db_manager = DatabaseManager()

# Request models
class EmailRequest(BaseModel):
    to_email: EmailStr
    subject: str
    template_name: str
    template_data: Dict[str, Any] = {}
    priority: str = "normal"  # "high", "normal", "low"

class BulkEmailRequest(BaseModel):
    template_name: str
    recipient_data: List[Dict[str, Any]]  # Each dict contains email and template data
    priority: str = "normal"

class DigestRequest(BaseModel):
    digest_type: str  # "daily", "weekly", "monthly"
    user_ids: Optional[List[str]] = None  # If None, send to all eligible users

# Email service endpoints
@email_app.get("/")
async def root():
    """Email service root endpoint"""
    return {
        "service": "ArXiv Email Service",
        "version": "1.0.0",
        "status": "online"
    }

@email_app.get("/health")
async def health_check():
    """Health check for email service"""
    try:
        # Check SMTP connection
        smtp_status = await email_manager.check_smtp_connection()
        
        # Check database connection
        db_status = await db_manager.check_connection()
        
        # Check email queue
        queue_status = await notification_processor.get_queue_status()
        
        return {
            "status": "healthy" if smtp_status and db_status else "degraded",
            "smtp": "connected" if smtp_status else "disconnected",
            "database": "connected" if db_status else "disconnected",
            "queue": queue_status,
            "timestamp": datetime.utcnow().isoformat()
        }
        
    except Exception as e:
        logger.error(f"Health check failed: {e}")
        return {
            "status": "unhealthy",
            "error": str(e),
            "timestamp": datetime.utcnow().isoformat()
        }

@email_app.post("/send")
async def send_email(email_request: EmailRequest, background_tasks: BackgroundTasks):
    """Send a single email"""
    try:
        # Add email to processing queue
        background_tasks.add_task(
            notification_processor.process_single_email,
            email_request.dict()
        )
        
        return {
            "success": True,
            "message": "Email queued for processing",
            "recipient": email_request.to_email
        }
        
    except Exception as e:
        logger.error(f"Failed to queue email: {e}")
        raise HTTPException(status_code=500, detail="Failed to queue email")

@email_app.post("/send-bulk")
async def send_bulk_email(bulk_request: BulkEmailRequest, background_tasks: BackgroundTasks):
    """Send bulk emails with same template"""
    try:
        # Add bulk email job to queue
        background_tasks.add_task(
            notification_processor.process_bulk_emails,
            bulk_request.dict()
        )
        
        return {
            "success": True,
            "message": "Bulk emails queued for processing",
            "recipient_count": len(bulk_request.recipient_data)
        }
        
    except Exception as e:
        logger.error(f"Failed to queue bulk emails: {e}")
        raise HTTPException(status_code=500, detail="Failed to queue bulk emails")

@email_app.post("/digest/{digest_type}")
async def send_digest(
    digest_type: str, 
    user_ids: Optional[List[str]] = None, 
    background_tasks: BackgroundTasks = None
):
    """Send digest emails (daily, weekly, monthly)"""
    if digest_type not in ["daily", "weekly", "monthly"]:
        raise HTTPException(status_code=400, detail="Invalid digest type")
    
    try:
        # Add digest generation to queue
        background_tasks.add_task(
            notification_processor.generate_and_send_digest,
            digest_type,
            user_ids
        )
        
        return {
            "success": True,
            "message": f"{digest_type.capitalize()} digest queued for processing",
            "digest_type": digest_type
        }
        
    except Exception as e:
        logger.error(f"Failed to queue digest: {e}")
        raise HTTPException(status_code=500, detail="Failed to queue digest")

@email_app.get("/queue/status")
async def get_queue_status():
    """Get email queue status"""
    try:
        status = await notification_processor.get_queue_status()
        return status
    except Exception as e:
        logger.error(f"Failed to get queue status: {e}")
        raise HTTPException(status_code=500, detail="Failed to get queue status")

@email_app.get("/templates")
async def list_templates():
    """List available email templates"""
    try:
        templates = await template_manager.list_templates()
        return {
            "templates": templates,
            "count": len(templates)
        }
    except Exception as e:
        logger.error(f"Failed to list templates: {e}")
        raise HTTPException(status_code=500, detail="Failed to list templates")

@email_app.get("/templates/{template_name}")
async def get_template(template_name: str):
    """Get email template details"""
    try:
        template = await template_manager.get_template(template_name)
        if not template:
            raise HTTPException(status_code=404, detail="Template not found")
        return template
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get template: {e}")
        raise HTTPException(status_code=500, detail="Failed to get template")

@email_app.get("/stats")
async def get_email_stats():
    """Get email delivery statistics"""
    try:
        stats = await get_email_statistics()
        return stats
    except Exception as e:
        logger.error(f"Failed to get email stats: {e}")
        raise HTTPException(status_code=500, detail="Failed to get email stats")

@email_app.post("/test-email")
async def send_test_email(test_email: EmailStr, background_tasks: BackgroundTasks):
    """Send test email for configuration verification"""
    try:
        test_data = {
            "to_email": test_email,
            "subject": "ArXiv Email Service Test",
            "template_name": "test_email",
            "template_data": {
                "test_time": datetime.utcnow().isoformat(),
                "service_name": "ArXiv Email Service"
            }
        }
        
        background_tasks.add_task(
            notification_processor.process_single_email,
            test_data
        )
        
        return {
            "success": True,
            "message": f"Test email sent to {test_email}"
        }
        
    except Exception as e:
        logger.error(f"Failed to send test email: {e}")
        raise HTTPException(status_code=500, detail="Failed to send test email")

# Background service functions
async def get_email_statistics() -> Dict[str, Any]:
    """Get comprehensive email statistics"""
    try:
        async with db_manager.get_connection() as conn:
            async with conn.cursor() as cur:
                stats = {}
                
                # Total emails sent (last 30 days)
                await cur.execute("""
                    SELECT COUNT(*) 
                    FROM email_delivery_logs 
                    WHERE sent_at >= NOW() - INTERVAL '30 days'
                    AND status = 'delivered'
                """)
                result = await cur.fetchone()
                stats['emails_sent_30_days'] = result['count']
                
                # Email delivery rate
                await cur.execute("""
                    SELECT 
                        status,
                        COUNT(*) as count
                    FROM email_delivery_logs 
                    WHERE sent_at >= NOW() - INTERVAL '7 days'
                    GROUP BY status
                """)
                results = await cur.fetchall()
                status_counts = {row['status']: row['count'] for row in results}
                
                total_attempts = sum(status_counts.values())
                delivered = status_counts.get('delivered', 0)
                stats['delivery_rate_7_days'] = (delivered / total_attempts * 100) if total_attempts > 0 else 0
                
                # Queue status
                await cur.execute("""
                    SELECT 
                        status,
                        COUNT(*) as count
                    FROM notification_queue
                    GROUP BY status
                """)
                results = await cur.fetchall()
                stats['queue_status'] = {row['status']: row['count'] for row in results}
                
                # Popular email types
                await cur.execute("""
                    SELECT 
                        template_name,
                        COUNT(*) as count
                    FROM email_delivery_logs 
                    WHERE sent_at >= NOW() - INTERVAL '7 days'
                    GROUP BY template_name
                    ORDER BY count DESC
                    LIMIT 10
                """)
                results = await cur.fetchall()
                stats['popular_templates'] = [dict(row) for row in results]
                
                return stats
                
    except Exception as e:
        logger.error(f"Failed to get email statistics: {e}")
        return {}

async def run_background_tasks():
    """Run background email processing tasks"""
    logger.info("Starting email service background tasks")
    
    # Start notification processor
    await notification_processor.start_processing()
    
    # Schedule digest emails
    await schedule_digest_emails()

async def schedule_digest_emails():
    """Schedule automatic digest emails"""
    try:
        # Daily digest at 8 AM
        # Weekly digest on Mondays at 9 AM
        # Monthly digest on 1st of month at 10 AM
        
        # This would be implemented with a proper task scheduler
        # For now, we'll use a simple loop
        
        while True:
            current_time = datetime.utcnow()
            
            # Check for daily digest (8 AM UTC)
            if current_time.hour == 8 and current_time.minute == 0:
                await notification_processor.generate_and_send_digest("daily")
            
            # Check for weekly digest (Monday 9 AM UTC)
            elif current_time.weekday() == 0 and current_time.hour == 9 and current_time.minute == 0:
                await notification_processor.generate_and_send_digest("weekly")
            
            # Check for monthly digest (1st day, 10 AM UTC)
            elif current_time.day == 1 and current_time.hour == 10 and current_time.minute == 0:
                await notification_processor.generate_and_send_digest("monthly")
            
            # Sleep for 1 minute
            await asyncio.sleep(60)
            
    except Exception as e:
        logger.error(f"Digest scheduling failed: {e}")

# Application startup
@email_app.on_event("startup")
async def startup_event():
    """Initialize email service on startup"""
    logger.info("Starting ArXiv Email Service")
    
    # Initialize services
    await email_manager.initialize()
    await notification_processor.initialize()
    await template_manager.initialize()
    
    # Start background tasks
    asyncio.create_task(run_background_tasks())

@email_app.on_event("shutdown")
async def shutdown_event():
    """Cleanup on shutdown"""
    logger.info("Shutting down ArXiv Email Service")
    
    # Stop background processing
    await notification_processor.stop_processing()
    
    # Close connections
    await db_manager.close_connections()

if __name__ == "__main__":
    port = int(config.system.storage_path.get("EMAIL_SERVICE_PORT", 8001))
    uvicorn.run(
        "email_service.main:email_app",
        host="0.0.0.0",
        port=port,
        reload=config.system.debug,
        log_level=config.system.log_level.lower()
    )